import 'dart:convert';

import 'package:dio/dio.dart';

class CommonHeaderInterceptor extends Interceptor {
  static String? token = "";
  static var language_key = 'language';
  static String language = 'en';

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.headers[language_key] = language;
    options.headers['token'] = token;
    super.onRequest(options, handler);
  }
}

class MyLogInterceptor extends Interceptor {
  MyLogInterceptor({
    this.request = true,
    this.requestHeader = true,
    this.requestBody = true,
    this.responseHeader = true,
    this.responseBody = true,
    this.error = true,
    this.logPrint = print,
  });

  /// Print request [Options]
  bool request;

  /// Print request header [Options.headers]
  bool requestHeader;

  /// Print request data [Options.data]
  bool requestBody;

  /// Print [Response.data]
  bool responseBody;

  /// Print [Response.headers]
  bool responseHeader;

  /// Print error message
  bool error;

  /// Log printer; defaults print log to console.
  /// In flutter, you'd better use debugPrint.
  /// you can also write log in a file, for example:
  ///```dart
  ///  var file=File("./log.txt");
  ///  var sink=file.openWrite();
  ///  dio.interceptors.add(LogInterceptor(logPrint: sink.writeln));
  ///  ...
  ///  await sink.close();
  ///```
  void Function(Object object) logPrint;

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    logPrint('*** Request ***');
    _printKV('url', options.uri);
    //options.headers;

    if (request) {
      _printKV('method', options.method);
      _printKV('responseType', options.responseType.toString());
      _printKV('followRedirects', options.followRedirects);
      _printKV('connectTimeout', options.connectTimeout);
      _printKV('sendTimeout', options.sendTimeout);
      _printKV('receiveTimeout', options.receiveTimeout);
      _printKV('receiveDataWhenStatusError', options.receiveDataWhenStatusError);
      _printKV('extra', options.extra);
    }
    if (requestHeader) {
      logPrint('headers:');
      options.headers.forEach((key, v) => _printKV(' $key', v));
    }
    if (requestBody) {
      logPrint('body:');
      _printRequestBody(options.data);
      // _printLong(json.encode(options.data));

      if (options.data is FormData) {
        for (var element in (options.data as FormData).fields) {
          _printLong('${element.key}:${element.value}');
        }
      }
    }
    logPrint('');

    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) async {
    logPrint('*** Response ***');
    _printResponse(response);
    handler.next(response);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) async {
    if (error) {
      logPrint('*** DioError ***:');
      logPrint('url: ${err.requestOptions.uri}');
      logPrint('$err');
      if (err.response != null) {
        _printResponse(err.response!);
      }
      logPrint('');
    }

    handler.next(err);
  }

  void _printResponse(Response response) {
    _printKV('url', response.requestOptions.uri);
    _printKV('statusCode', response.statusCode);
    if (responseHeader) {
      // _printKV('statusCode', response.statusCode);
      if (response.isRedirect == true) {
        _printKV('redirect', response.realUri);
      }

      logPrint('headers:');
      response.headers.forEach((key, v) => _printKV(' $key', v.join('\r\n\t')));
    }
    if (responseBody) {
      logPrint('Response Text:');
      _printResponseBody(response);
    }
    logPrint('');
  }

  void _printKV(String key, Object? v) {
    logPrint('$key: $v');
  }

  void _printAll(msg) {
    msg.toString().split('\n').forEach(logPrint);
  }

  void _printLong(String text) {
    const int maxLength = 1000; // 每段打印长度
    if (text.length <= maxLength) {
      logPrint(text);
    } else {
      int start = 0;
      while (start < text.length) {
        int end = start + maxLength;
        if (end > text.length) end = text.length;
        logPrint(text.substring(start, end));
        start = end;
      }
    }
  }

  /// 打印请求参数，优化格式以便于复制和查看
  void _printRequestBody(dynamic data) {
    try {

      // 如果响应体是字符串，尝试解析为 JSON
      if (data is String) {
        // 尝试格式化 JSON
        try {
          final jsonData = json.decode(data);
          final formattedJson = const JsonEncoder.withIndent('  ').convert(jsonData);
          logPrint('═══════════════════════════════════════════════════════════');
          logPrint(formattedJson);
          logPrint('═══════════════════════════════════════════════════════════');
        } catch (e) {
          // 如果不是 JSON，直接打印字符串
          logPrint('═══════════════════════════════════════════════════════════');
          _printLong(data);
          logPrint('═══════════════════════════════════════════════════════════');
        }
      }
      // 如果响应体已经是 Map 或 List，直接格式化
      else if (data is Map || data is List) {
        final formattedJson = const JsonEncoder.withIndent('  ').convert(data);
        logPrint('═══════════════════════════════════════════════════════════');
        logPrint(formattedJson);
        logPrint('═══════════════════════════════════════════════════════════');
      }
      // 其他类型直接转换为字符串打印
      else {
        logPrint('═══════════════════════════════════════════════════════════');
        _printLong(data.toString());
        logPrint('═══════════════════════════════════════════════════════════');
      }
    } catch (e) {
      // 如果格式化失败，使用原始方式打印
      logPrint('═══════════════════════════════════════════════════════════');
      _printLong(data?.toString() ?? '');
      logPrint('═══════════════════════════════════════════════════════════');
    }
  }

  /// 打印响应体，优化格式以便于复制和查看
  void _printResponseBody(Response response) {
    try {
      dynamic data = response.data;
      
      // 如果响应体是字符串，尝试解析为 JSON
      if (data is String) {
        // 尝试格式化 JSON
        try {
          final jsonData = json.decode(data);
          final formattedJson = const JsonEncoder.withIndent('  ').convert(jsonData);
          logPrint('═══════════════════════════════════════════════════════════');
          logPrint(formattedJson);
          logPrint('═══════════════════════════════════════════════════════════');
        } catch (e) {
          // 如果不是 JSON，直接打印字符串
          logPrint('═══════════════════════════════════════════════════════════');
          _printLong(data);
          logPrint('═══════════════════════════════════════════════════════════');
        }
      } 
      // 如果响应体已经是 Map 或 List，直接格式化
      else if (data is Map || data is List) {
        final formattedJson = const JsonEncoder.withIndent('  ').convert(data);
        logPrint('═══════════════════════════════════════════════════════════');
        logPrint(formattedJson);
        logPrint('═══════════════════════════════════════════════════════════');
      } 
      // 其他类型直接转换为字符串打印
      else {
        logPrint('═══════════════════════════════════════════════════════════');
        _printLong(data.toString());
        logPrint('═══════════════════════════════════════════════════════════');
      }
    } catch (e) {
      // 如果格式化失败，使用原始方式打印
      logPrint('═══════════════════════════════════════════════════════════');
      _printLong(response.data?.toString() ?? response.toString());
      logPrint('═══════════════════════════════════════════════════════════');
    }
  }

}
